from backtrader import BrokerBase, OrderBase, Order
from backtrader.utils.maths import *


class CCXTFutureOrder(OrderBase):
    """
    order里面有一个参数closeposition为true，代表所有仓位
    """
    def __init__(self, owner, data, ccxt_order, args, mapping, orders_type):
        self.owner = owner
        self.data = data
        self.ccxt_order = ccxt_order
        self.args = args
        self.executed_fills = []
        self.mapping = mapping

        # 提交订单时间, 取自交易所的创建时间
        # 合约市价成交的时候, 这个字段不存在, 只能使用trade_time
        if mapping["order_result"]["order_time"] in ccxt_order["info"]:
            self.order_time = float(ccxt_order["info"][mapping["order_result"]["order_time"]])
        else:
            self.order_time = float(ccxt_order["info"][mapping["order_result"]["trade_time"]])

        # 成交时间, 取自交易所的交易时间
        self.trade_time = float(ccxt_order["info"][mapping["order_result"]["trade_time"]])

        ordtype = ccxt_order[mapping["order_result"]["side"]]
        self.ordtype = self.Buy if ordtype == 'buy' else self.Sell
        # self.size = float(ccxt_order['amount'])

        self.id = ccxt_order[mapping["order_result"]["id"]]

        _price = ccxt_order[mapping["order_result"]["price"]]            # 委托价
        _plimit = ccxt_order[mapping["order_result"]["stop_price"]]      # 止损触发价
        _size = ccxt_order[mapping["order_result"]["size"]]              # 委托数量
        exectype_key = ccxt_order[mapping["order_result"]["exectype"]]

        # 将交易所的执行类型转成标准类型
        reverse_mapping = {v: k for k, v in orders_type.items()}
        _exectype = reverse_mapping[exectype_key]

        self.price = _price
        self.pricelimit = _plimit       #  这里必须使用pricelimit, 不能用plimit, 见orderbase selp.plimit初始化代码
        self.exectype = _exectype
        self.size = _size

        # price=price, pricelimit=pricelimit, size=size, exectype=exectype
        super(CCXTFutureOrder, self).__init__()

    def fix_time(self, ccxt_order):
        if self.mapping["order_result"]["order_time"] in ccxt_order["info"]:
            self.order_time = float(ccxt_order["info"][self.mapping["order_result"]["order_time"]])
        else:
            self.order_time = float(ccxt_order["info"][self.mapping["order_result"]["trade_time"]])

        # 成交时间, 取自交易所的交易时间
        self.trade_time = float(ccxt_order["info"][self.mapping["order_result"]["trade_time"]])


class CCXTOrder(OrderBase):
    def __init__(self, owner, data, ccxt_order, args, mapping, orders_type):
        self.owner = owner
        self.data = data
        self.ccxt_order = ccxt_order
        self.args = args
        self.executed_fills = []

        # 提交订单时间, 取自交易所的创建时间
        self.order_time = float(ccxt_order["info"][mapping["order_result"]["order_time"]])
        # 成交时间, 取自交易所的交易时间
        self.trade_time = float(ccxt_order["info"][mapping["order_result"]["trade_time"]])

        ordtype = ccxt_order[mapping["order_result"]["side"]]
        self.ordtype = self.Buy if ordtype == 'buy' else self.Sell
        # self.size = float(ccxt_order['amount'])

        self.id = ccxt_order[mapping["order_result"]["id"]]

        _price = ccxt_order[mapping["order_result"]["price"]]            # 委托价
        _plimit = ccxt_order[mapping["order_result"]["stop_price"]]      # 止损触发价
        _size = ccxt_order[mapping["order_result"]["size"]]              # 委托数量
        exectype_key = ccxt_order[mapping["order_result"]["exectype"]]

        # 将交易所的执行类型转成标准类型
        reverse_mapping = {v: k for k, v in orders_type.items()}
        _exectype = reverse_mapping[exectype_key]

        self.price = _price
        self.pricelimit = _plimit       #  这里必须使用pricelimit, 不能用plimit, 见orderbase selp.plimit初始化代码
        self.exectype = _exectype
        self.size = _size

        # price=price, pricelimit=pricelimit, size=size, exectype=exectype
        super(CCXTOrder, self).__init__()


class Okex5CCXTOrder(OrderBase):
    conditional, oco = "conditional", "oco"

    def __init__(self, owner, data, ccxt_order, args, mapping, orders_type):
        self.owner = owner
        self.data = data
        self.ccxt_order = ccxt_order
        self.ref_order: CCXTOrder = None           # 止损单触发的时候的普通委托单
        self.args = args
        self.executed_fills = []

        ordtype = ccxt_order[mapping["order_strat_result"]["side"]]
        self.ordtype = self.Buy if ordtype == 'buy' else self.Sell
        # self.size = float(ccxt_order['amount'])

        self.id = ccxt_order[mapping["order_strat_result"]["id"]]

        # 提交订单时间, 取自交易所的创建时间
        self.order_time = float(ccxt_order[mapping["order_strat_result"]["order_time"]])
        # 成交时间, 取自交易所的交易时间, 这里是触发时间
        self.trade_time = None

        self.loss_price = floatnone(ccxt_order[mapping["order_strat_result"]["loss_price"]])
        self.trigger_loss_price = floatnone(ccxt_order[mapping["order_strat_result"]["trigger_loss_price"]])
        self.profit_price = floatnone(ccxt_order[mapping["order_strat_result"]["profit_price"]])
        self.trigger_profit_price = floatnone(ccxt_order[mapping["order_strat_result"]["trigger_profit_price"]])

        self.trigger_time = None

        exectype = ccxt_order[mapping["order_strat_result"]["exectype"]]

        if self.trigger_profit_price and self.profit_price and self.profit_price != -1 and \
            self.trigger_loss_price and self.loss_price and self.loss_price != -1 and exectype == Okex5CCXTOrder.oco:
            _price = self.loss_price
            _plimit = self.trigger_loss_price
            _exectype = Order.StopProfitLimit
        elif self.trigger_profit_price and self.profit_price and self.profit_price == -1 and \
            self.trigger_loss_price and self.loss_price and self.loss_price == -1 and exectype == Okex5CCXTOrder.oco:
            _price = self.loss_price
            _plimit = self.trigger_loss_price
            _exectype = Order.StopProfit
        elif self.trigger_profit_price and self.profit_price and self.profit_price == -1 and exectype == Okex5CCXTOrder.conditional:
            _price = self.profit_price
            _plimit = self.trigger_profit_price
            _exectype = Order.Profit
        elif self.trigger_profit_price and self.profit_price and self.profit_price != -1 and exectype == Okex5CCXTOrder.conditional:
            _price = self.profit_price
            _plimit = self.trigger_profit_price
            _exectype = Order.ProfitLimit
        elif self.trigger_loss_price and self.loss_price and self.loss_price == -1 and exectype == Okex5CCXTOrder.conditional:
            _price = self.loss_price
            _plimit = self.trigger_loss_price
            _exectype = Order.Stop
        elif self.trigger_loss_price and self.loss_price and self.loss_price != -1 and exectype == Okex5CCXTOrder.conditional:
            _price = self.loss_price
            _plimit = self.trigger_loss_price
            _exectype = Order.StopLimit
        _size = floatzero(ccxt_order[mapping["order_strat_result"]["size"]])  # 委托数量

        self.price = _price
        self.pricelimit = _plimit
        self.exectype = _exectype
        self.size = _size

        super(Okex5CCXTOrder, self).__init__()


    def trigger(self, trigger_time, order: CCXTOrder):
        super(Okex5CCXTOrder, self).trigger(trigger_time, order)
        self.ref_order = order
        self.trigger_time = float(trigger_time) if trigger_time else None
        self.trade_time = self.trigger_time

    def cancel(self):
        super(Okex5CCXTOrder, self).cancel()
        if self.ref_order:
            self.ref_order.cancel()

    def completed(self):
        super(Okex5CCXTOrder, self).completed()
        if self.ref_order:
            self.ref_order.completed()